//
//  vdNode.h
//  Void Dead
//
//  Created by Sidney Just on 17.11.09.
//
//  Copyright © 2009 by Sidney Just
//  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
//  documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
//  the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 
//  and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
//  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
//  PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
//  FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
//  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

#import <Foundation/Foundation.h>

#import "vdView.h"
#import "vdColor.h"
#import "vdKernel.h"
#import "vdShader.h"

#import "vdAction.h"

#import "vdEventReceiver.h"
#import "vdEventHandler.h"

#define SHOW 1
#define BRIGHT 2
#define BLEND 4
#define AFFECTCHILDREN 8
#define IGNOREACTIONS 16

/**
 * This class implements one of the core elements of Void Dead. As Void Dead uses a node system to manage objects, vdNode is the base element for almost all objects.
 * <br>A node is by default a void object. But you can use a node to display a texture or a button on the screen, by using one of it's subclasses.
 **/

@interface vdNode : NSObject <vdEventProtocol> {
	//\cond
	vdNode		*parent;
	vdNode		**children;
	int			count;
	
	int	layer;
	
	float pos_x;
	float pos_y;
	
	float aPos_x;
	float aPos_y;
	
	float size_x;
	float size_y;
	
	float rotation;
	
	float scale_x;
	float scale_y;
	
	GLfloat	*modelMatrix;
	
	vdView		*mother;
	vdKernel	*father;

	vdColor	*color;
	vdTexNode	*texture;
	
	vdShader	*nodeShader;
	GLenum		sourceBlendF;
	GLenum		destBlendF;
	
	vdRenderTarget	*renderTarget;
	unsigned int	flags;
	
	vdEventReceiver *receiver;
	/**
	 * The number of nodes which implements the vdGUIProtocol
	 **/
	int uiChilds;
	
	vdAction **action;
	int actions;
	
	vdAction *currentAction;
	//\endcond
}

/**
 * Implemented for future use
 **/
@property GLfloat *modelMatrix;

/**
 * The current running action, if no action is running this variable will be NULL
 **/
@property (readonly) vdAction *currentAction;

/**
 * The event receiver of the node. This is NULL by default and will be created when you attach a node wich conforms to the vdGUIProtocol.
 **/
@property (readonly) vdEventReceiver *receiver;

/**
 * The render target of the node. Default: NULL
 @remark The render target will be assigned to all childs and subchilds of the node!
 **/
@property vdRenderTarget *renderTarget;

/**
 * The shader of the node. By default this is NULL and will cause the engine to use the default shader that will render the object just like the fixed function rendering version.
 **/
@property (nonatomic, retain) vdShader *nodeShader;

/**
 * The scale of the node on the x axis. Default 1
 @remark The scale can but doesn't have to be respected by a node! When you want to respect the scale in your drawing function, you can use something like size_x*scale_x
 **/
@property float scale_x;

/**
 * The scale of the node on the y axis. Default 1
 @remark The scale can but doesn't have to be respected by a node! When you want to respect the scale in your drawing function, you can use something like size_y*scale_y
 **/
@property float scale_y;

/**
 * The rotation of the node in degrees. Default 0
 **/
@property float rotation;

/**
 * The vdKernel where the vdNode is inserted into (NULL or sharedKernel)
 **/
@property (nonatomic, retain) vdKernel *father;

/**
 * The color of the node.
 **/
@property vdColor *color;

/**
 * The source blend factor of the node
 * @remark Default is GL_SRC_ALPHA
 **/
@property GLenum sourceBlendF;

/**
 * The source destination blend factor of the node
 * @remark Default is GL_SRC_MINUS_ONE_ALPHA
 **/
@property GLenum destBlendF;

/**
 * The texture of the node. Default = NULL;
 **/
@property (nonatomic, readonly) vdTexNode *texture;

/**
 * The flags of the node. Flags determine the behavior of a node. Possible flags are:
 * <br>SHOW = The node is visible (default!)
 * <br>BRIGHT = The blending will be changed to GL_SRC_ALPHA, GL_DST_ALPHA without changing sourceBlendF and destBlendF!
 * <br>BLEND = GL_BLEND will be enabled for this node, the node will be use sourceBlendF and destBlendF for the blending (default!)
 * <br>AFFECTCHILDREN = If the node is invisible, all childs and subchilds are also invisible (default!)
 * <br>IGNOREACTION = Forces the node to not execute its vdActions
 @remark Flags must be set as a OR bitmas. Eg: vdNode.flags |= BRIGHT or vdNode.flags &= ~BRIGHT.
 **/
@property unsigned int flags;

/**
 * The parent is the vdNode thats contains this vdNode as child.
 **/
@property (nonatomic, retain) vdNode *parent;

/**
 * The layer of the object. By default it's 0. Objects with higher layers gets drawn over objects with lower layers! To set the layer call reorderChild in the vdNode that contains this vdNode.
 **/
@property int layer;

/**
 * The mother is the vdView where the child draws into, or NULL if it isn't attached to a view.
 **/
@property (nonatomic, retain) vdView *mother;

/**
 * Absolute position of the node on the screen
 **/
@property float aPos_x;

/**
 * Absolute position of the node on the screen
 **/
@property float aPos_y;

/**
 * Position of the node relative to it's parent on the x-axis
 **/
@property float pos_x;
/**
 * Position of the node relative to it's parent on the y-axis
 **/
@property float pos_y;

/**
 * Width in pixels
 **/
@property float size_x;
/**
 * Height in pixels
 **/
@property float size_y;

/**
 * The vdNodes that are attached to this node
 **/
@property (nonatomic) vdNode **children;

/**
 * The number of children.
 **/
@property int count;


/**
 * Allocates, init and returns a vdNode.
 @return A new vdNode object.
 **/
+ (vdNode *)node;

/**
 * Contacts all children and fires theire draw command
 **/
- (void)contact:(CGPoint)p :(NSTimeInterval)deltaTime;

/**
 * Removes and releases all children attached to the node. 
 @remark Even if a child is retained, it will be released!
 **/
- (void)cleanChildren;

/**
 * This will remove and release the node and all its childs. If the node has a parent node, it will remove itself from its parent!
 @remark Even if the node or a child is retained, it will be released!
 **/
- (void)destroy;

/**
 * Adds a vdNode as a child to this node with the given layer.
 @param aNode The node that should be attached to this node.
 @param aLayer The layer for the child. Objects with higher layers gets drawn over objects with lower layers!
 **/
- (void)addChild:(vdNode *)aNode withLayer:(int)aLayer;

/**
 * Adds a vdNode as a child with a default (0) layer
 @param aNode The node that should be attached to this node.
 **/
- (void)addChild:(vdNode *)aNode;

/**
 * Removes a child from the node.
 @param aNode The cild that should be removed
 @param clean If YES, the child and all it's children will be released (even if you retained it!), if NO, neither the children nor its children will be released!
 **/
- (void)removeChild:(vdNode *)aNode cleanUp:(BOOL)clean;

/**
 * Reorders a child.
 @param aChild The node that should be reorderd.
 @param aLayer The new layer for the child.
 **/
- (void)reorderChild:(vdNode *)aChild toLayer:(int)aLayer;

/**
 * Returns the next child after a given child. This can be used to loop through all childs in the node.
 @param node The child from what you want to have the next child or NULL if you want the first child of the node.
 @return The next child of the node or NULL if the given chikd is the last child or not a child of the node.
 **/
- (vdNode *)nextNode:(vdNode *)node;

/**
 * Adds the given action to the node. The action will be executed before the node gets drawn.
 @param _action The action you want to add. (Note: You can one action only one time to a node!)
 **/
- (void)addAction:(vdAction *)_action;

/**
 * Removes the given action from the node.
 @param _action The action you want to remove
 **/
- (void)removeAction:(vdAction *)_action;

@end

/**
 * The GUI protocol. All nodes that implement this protocol and are attached to a vdNode will receive the messages
 **/
@protocol vdGUIProtocol
@optional
/**
 * The user has touched on the given position and still holds his finger there
 @param point The position of the touch
 **/
- (void)getTouch:(CGPoint)point;

/**
 * The user has released his finges from the screen. The given point is the last position of the finger
 @param point The position of the touch
 **/
- (void)endSequence:(CGPoint)point;
@end

@class vdButton;
@class vdCheckbox;
@class vdTextField;

/**
 * This protocol must be implemented if you want to receive messages from nodes like vdButton or vdCheckbox
 **/
@protocol vdInterfaceProtocol
@optional
/**
 * The user has "clicked" on the given button
 @param sender The button on which the user has touched
 **/
- (void)buttonTouchUpInside:(vdButton *)sender;

/**
 * The user has "clicked" on the given checkbox and has triggered a state change
 @param sender The checkbox on which the user has touched
 **/
- (void)checkBoxChangedState:(vdCheckbox *)sender;

/**
 * The user has changed the text in the given text field
 @param sender The text field that has invoked the event
 **/
- (void)textFieldChangedCharacter:(vdTextField *)sender;
@end
